package com.campus.service.impl;

import com.campus.constant.MessageConstant;
import com.campus.constant.RoleConstant;
import com.campus.context.CurrentHolder;
import com.campus.exception.*;
import com.campus.mapper.CourseMapper;
import com.campus.mapper.UserCourseMapper;
import com.campus.pojo.entity.Course;
import com.campus.pojo.entity.UserCourse;
import com.campus.pojo.vo.CourseVO;
import com.campus.service.CourseService;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.time.LocalTime;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

@Service
@Slf4j
public class CourseServiceImpl implements CourseService {

    @Autowired
    private CourseMapper courseMapper;
    @Autowired
    private UserCourseMapper userCourseMapper;

    @Override
    public void importCourses(MultipartFile file) {
        // 检查文件是否为空
        if (file.isEmpty()) {
            throw new FileNotFoundException(MessageConstant.FILE_NOT_FOUND);
        }

        try {
            Workbook workbook = new XSSFWorkbook(file.getInputStream());
            Sheet sheet = workbook.getSheetAt(0); // 第一个 sheet

            // 指向第0行（即Excel第1行） 与集合迭代器类似
            Iterator<Row> rows = sheet.iterator();

            // 判断是否有数据
            //hasNext(): 当前位置是否有数据？
            if (!rows.hasNext()) {
                throw new ExcelDataEmptyException(MessageConstant.EXCEL_DATA_EMPTY);
            }

            // 检查表头
            // next(): 取出当前位置的行数据 并移动到下一行
            Row headerRow = rows.next();
            if (!isValidHeader(headerRow)) {
                throw new ExcelHeaderErrorException(MessageConstant.EXCEL_HEADER_ERROR);
            }

            // 遍历数据行 并插入数据库
            while (rows.hasNext()) {
                Row row = rows.next();

                // 判断是否为空行：检查第一列是否为空
                Cell firstCell = row.getCell(0);
                String firstCellValue = getCellValue(firstCell);

                if (firstCellValue == null || firstCellValue.trim().isEmpty()) {
                    log.info("跳过空行：第 {} 行", row.getRowNum() + 1);
                    continue; // 跳过空行
                }


                log.info("开始处理第 {} 行数据！", row.getRowNum() + 1);//程序中行数索引是从0开始的
                try {
                    Course course = parseRowToCourse(row);
                    if (course != null) {
                        //向course表中插入一条数据
                        courseMapper.insertCourse(course);

                        //向user_course表中插入一条数据
                        UserCourse userCourse = UserCourse.builder()
                                .userId(CurrentHolder.getCurrentId())
                                .courseId(course.getId())
                                .build();

                        userCourseMapper.insert(userCourse);

                    }
                } catch (Exception e) {
                    //索引是从0开始
                    log.info("解析第 {} 行失败, 异常信息：{}", row.getRowNum() + 1, e.getMessage());
                    throw new ExcelParseException(MessageConstant.EXCEL_PARSE_ERROR);
                }
            }
        } catch (Exception e) {
            log.error("解析失败：{}", e.getMessage());
            throw new BaseException(MessageConstant.EXCEL_PARSE_ERROR);
        }

    }

    @Override
    public List<CourseVO> getCourses() {
        //如果是管理员 则获取所有课程
        Long userId = CurrentHolder.getCurrentId();
        if (userId == RoleConstant.ADMIN_ROLE_ID) {
            return courseMapper.getCourses();
        } else {
            return userCourseMapper.getCoursesById(userId);
        }


    }

    @Override
    public void downloadTemplate(HttpServletResponse response) {
        //1.该代码用于读取项目资源目录下的Excel模板文件 通过类加载器可以正确地定位和加载位于classpath中的资源文件  建立了程序与该文件的通道
        //为什么是输入流？ 因为我要将文件读进来 读到程序中
        InputStream in = this.getClass().getClassLoader().getResourceAsStream("template/课表标准模板.xlsx");


        try {

            //2.基于文件输入流创建工作簿 即一个新的excel文件
            Workbook excel = new XSSFWorkbook(in);

            //3.通过response对象创建一个输出流对象 连接服务器程序和客户端
            //为什么是输出流？ 因为我要将文件输出给客户端（写出去）
            ServletOutputStream out = response.getOutputStream();

            // 设置内容类型 告诉浏览器响应内容是Excel文件格式
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");

            /**
             * Content-Disposition: attachment 表示浏览器应该将响应内容作为附件处理，即触发文件下载对话框
             * 设置下载头（filename 最好用英文） 指示浏览器以附件形式下载文件 指定下载文件的默认名称
             */
            response.setHeader("Content-Disposition", "attachment; filename=course_template.xlsx");

            //4.将整个Excel的内容写入到指定的输出流中 服务端程序已经与客户端浏览器建立通道 然后输出流再将内容输出给客户端浏览器
            excel.write(out);

            //5.释放资源
            out.close();
            in.close();
            excel.close();


        } catch (Exception e) {
            log.error("创建工作簿失败：{}", e.getMessage());
        }


    }


    private boolean isValidHeader(Row headerRow) {
        return "课程名称".equals(getCellValue(headerRow.getCell(0))) &&
                "课程代码".equals(getCellValue(headerRow.getCell(1))) &&
                "授课教师".equals(getCellValue(headerRow.getCell(2))) &&
                "星期几".equals(getCellValue(headerRow.getCell(3))) &&
                "开始时间".equals(getCellValue(headerRow.getCell(4))) &&
                "结束时间".equals(getCellValue(headerRow.getCell(5))) &&
                "教室位置".equals(getCellValue(headerRow.getCell(6))) &&
                "周次范围".equals(getCellValue(headerRow.getCell(7)));
    }

    private Course parseRowToCourse(Row row) {
        try {
            String courseName = getCellValue(row.getCell(0));


            String courseCode = getCellValue(row.getCell(1));
            String teacher = getCellValue(row.getCell(2));

            Integer weekday = parseInt(getCellValue(row.getCell(3)));

            String startTimeStr = getCellValue(row.getCell(4));
            String endTimeStr = getCellValue(row.getCell(5));
            String classroom = getCellValue(row.getCell(6));
            String weeks = getCellValue(row.getCell(7));

            // 添加空值检查
            LocalTime startTime = null;
            if (startTimeStr != null && !startTimeStr.isEmpty()) {
                startTime = LocalTime.parse(startTimeStr);
            }

            LocalTime endTime = null;
            if (endTimeStr != null && !endTimeStr.isEmpty()) {
                endTime = LocalTime.parse(endTimeStr);
            }

            // 使用builder创建课程对象
            Course course = Course.builder()
                    .courseName(courseName)
                    .courseCode(courseCode)
                    .teacher(teacher)
                    .weekday(weekday)
                    .startTime(startTime)
                    .endTime(endTime)
                    .classroom(classroom)
                    .weeks(weeks)
                    .build();

            return course;

        } catch (Exception e) {
            log.info("发生异常：{}", e.getMessage());
            throw new ExcelParseException(MessageConstant.EXCEL_PARSE_ERROR);
        }
    }


    private String getCellValue(Cell cell) {
        // 检查传入的 Cell 对象是否为 null
        if (cell == null) return "";

        // 检查 Cell 的数据类型
        switch (cell.getCellTypeEnum()) {
            //字符串 类型
            case STRING:
                // getStringCellValue() 获取字符串值，并调用 trim() 去除首尾空格
                return cell.getStringCellValue().trim();
            //数值 类型
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    // 获取日期值并转换为标准时间格式
                    Date date = cell.getDateCellValue();
                    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
                    return sdf.format(date);
                } else {
                    // 如果是普通数字，转换为整数后转为字符串
                    return String.valueOf((int) cell.getNumericCellValue());
                }
            default:
                return "";
        }
    }


    private Integer parseInt(String value) {
        if (value == null || value.isEmpty()) return null;
        // 去除首尾空格 返回整数
        return Integer.parseInt(value.trim());
    }
}
